package com.ouyang.bo.api.util;

import com.nimbusds.jose.*;
import com.nimbusds.jose.crypto.MACSigner;
import com.nimbusds.jose.crypto.MACVerifier;
import com.nimbusds.jose.crypto.RSASSASigner;
import com.nimbusds.jose.crypto.RSASSAVerifier;
import com.nimbusds.jose.jwk.RSAKey;
import com.nimbusds.jose.jwk.gen.RSAKeyGenerator;
import net.minidev.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.PostConstruct;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * Token工具类
 * 生成，解析，加密等功能
 *
 * @author duanpj
 * @param
 * @date 2020/8/4 0004
 */
@RestController
@Component
@RequestMapping("/api/tokenUtil")
public class TokenUtils {

    private static final Logger logger = LoggerFactory.getLogger(TokenUtils.class);

    @Autowired
/*    private IRegisterUserService iRegisterUserService;*/
    private static TokenUtils tokenUtils;

    //关于工具类静态方法调用@Autowired注入的service类问题
    //参考链接：https://www.cnblogs.com/jpfss/p/11271473.html
    @PostConstruct
    public void init() {
        tokenUtils = this;
        /*tokenUtils.iRegisterUserService = this.iRegisterUserService;*/
    }


    /**
     * 1.创建一个32-byte的密匙
     */
    private static final byte[] secret = "geiwodiangasfdjsikolkjikolkijswe".getBytes();

    /**
     * 获得token
     * token生成规则:用户编号和UUID
     *
     * @param userCode 用户编号
     * @param uuId     UUID
     * @return
     */
    @GetMapping("/getToken")
    public static String getToken(String userCode, String uuId) {
        try {
            if(StringUtils.isEmpty(userCode)||
                StringUtils.isEmpty(uuId)
            ){
                return "参数为空";
            }

            Map<String, Object> map = new HashMap<>();
            SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.S");//设置日期格式
            logger.info("生成时间: " + df.format(new Date()));
            //建立载荷，这些数据根据业务，自己定义。
            map.put("userCode", userCode);
            map.put("uuId", uuId);
            //生成时间
            map.put("loginTime", df.format(new Date()));
            logger.info("getToken------------>" + map);
            String token = TokenUtils.creatTokenHS256(map);
            return token;
        } catch (JOSEException e) {
            e.printStackTrace();
        }
        return null;
    }

    //生成一个token
    public static String creatTokenHS256(Map<String, Object> payloadMap) throws JOSEException {

        //3.先建立一个头部Header
        /**
         * JWSHeader参数：1.加密算法法则,2.类型，3.。。。。。。。
         * 一般只需要传入加密算法法则就可以。
         * 这里则采用HS256
         *
         * JWSAlgorithm类里面有所有的加密算法法则，直接调用。
         */
        JWSHeader jwsHeader = new JWSHeader(JWSAlgorithm.HS256);

        //建立一个载荷Payload
        Payload payload = new Payload(new JSONObject(payloadMap));
        //将头部和载荷结合在一起
        JWSObject jwsObject = new JWSObject(jwsHeader, payload);
        //建立一个密匙

        JWSSigner jwsSigner = new MACSigner(secret);

        //签名
        jwsObject.sign(jwsSigner);

        //生成token
        return jwsObject.serialize();


    }

    //解析token
    @GetMapping("/analysisToken")
    public static Map<String, Object> analysisToken(String tokenResult) throws ParseException, JOSEException {
//        解析token
        JWSObject jwsObject = JWSObject.parse(tokenResult);
        //建立一个解锁密匙
        JWSVerifier jwsVerifier = new MACVerifier(secret);
        return verify(jwsObject, jwsVerifier);
    }

    /**
     * 验证token信息示例
     * {
     * "loginTime": "2020-03-04 19:10:49.272",
     * "uuId": "837458437994",
     * "userCode": "U100231001",
     * "Result": 0
     * }
     */
    private static Map<String, Object> verify(JWSObject jwsObject, JWSVerifier jwsVerifier) throws JOSEException {
        Map<String, Object> resultMap = new HashMap<>();
        //获取到载荷
        Payload payload = jwsObject.getPayload();
        //判断token
        if (jwsObject.verify(jwsVerifier)) {
            //载荷的数据解析成json对象。
            JSONObject jsonObject = payload.toJSONObject();
            if (jsonObject.containsKey("userCode")) {
                //用户编号
                resultMap.put("userCode", jsonObject.get("userCode").toString());
                //UUID
                resultMap.put("uuId", jsonObject.get("uuId").toString());
                //登录时间
                resultMap.put("loginTime", jsonObject.get("loginTime").toString());
                //数据库中保存的UUID
                /*String getUUID = tokenUtils.iRegisterUserService.getUUID(jsonObject.get("userCode").toString());*/
                String getUUID = "";
                if(StringUtils.isNotNull(getUUID)){
                    if(getUUID.equals(jsonObject.get("uuId").toString())){
                        //正常
                        resultMap.put("Result", 1);
                    }else{
                        //失效
                        resultMap.put("Result", 2);
                    }
                }else{
                    //token为空
                    resultMap.put("Result", 2);
                }
            }
        } else {
            //无效token
            resultMap.put("Result", 2);
        }
        return resultMap;
    }

    /**
     * 创建加密key
     */
    public static RSAKey getKey() throws JOSEException {
        RSAKeyGenerator rsaKeyGenerator = new RSAKeyGenerator(2048);
        RSAKey rsaJWK = rsaKeyGenerator.generate();
        return rsaJWK;
    }

    //进行token加密
    public static String creatTokenRS256(Map<String, Object> payloadMap, RSAKey rsaJWK) throws JOSEException {

        //私密钥匙
        JWSSigner signer = new RSASSASigner(rsaJWK);

        JWSObject jwsObject = new JWSObject(
                new JWSHeader.Builder(JWSAlgorithm.RS256).keyID(rsaJWK.getKeyID()).build(),
                new Payload(new JSONObject(payloadMap))
        );
        //进行加密
        jwsObject.sign(signer);

        String token = jwsObject.serialize();
        return token;
    }

    //验证token
    public static Map<String, Object> validRS256(String token, RSAKey rsaJWK) throws ParseException, JOSEException {
        //获取到公钥
        RSAKey rsaKey = rsaJWK.toPublicJWK();
        JWSObject jwsObject = JWSObject.parse(token);
        JWSVerifier jwsVerifier = new RSASSAVerifier(rsaKey);
        //验证数据
        return verify(jwsObject, jwsVerifier);
    }

}
